home *** CD-ROM | disk | FTP | other *** search
Wrap
<?php /** * "Main" class of the Parser collection. * * Note that a lot of communication is done using shared instance variables. * * @version $Id: PhpdocParser.php,v 1.3 2001/02/18 14:45:27 uw Exp $ */ class PhpdocParser extends PhpdocClassParser { /** * Name of the file currently parsed. * * Instead of passing the name of the current file by argument * PHPDoc uses this slot to communicate. Yeah I know, it's * the way methods should communicate, but it saves me a lot * a lot of work. * @var string Name of the file currently parsed. */ var $currentFile = ""; /** * Array of PHP Sourcecode Files to examine. * * The array keys hold the filenames, the array values the file content. * * @var array * @see parse() */ var $phpfiles = array(); /** * Mapping from classnames to filenames * * @var array */ var $classnamesToFilenames = array(); /** * Hash with the data of the current class tree (one parentclass with all children). * * @var array * @see $modules */ var $classes = array(); /** * List of all parentclasses found. * @var array */ var $baseclasses = array(); /** * List of all files containing classes. * * @var array */ var $classfiles = array(); /** * Hash of all class trees. * * @var array */ var $classtree = array(); /** * List of all files containing modules. * * @var array */ var $modulefiles = array(); /** * List of all module groups. * * @var array */ var $modulegroups = array(); /** * Hash with the data of the current module group. * * @var array * @see $classes */ var $modules = array(); /** * Hash of all packages found. * * @var array */ var $packages = array(); /** * Flag indicating that getClassTree() was called. * * @var boolean * @see getClassTree() */ var $flag_classtree = false; /** * Flag indicating that getModulegroup was called. * * @var boolean * @see getModulegroup() */ var $flag_modulegroup = false; /** * Name of the base class of the current class tree. * * @var string * @see getClassTree() */ var $current_baseclass = ""; /** * Creates an instance of PhpdocWarning and calls buildComplexRegExps() to initialize the object. * * @param boolean If true the parser prints status messages. * @see $warn, buildComplexRegExps() */ function PhpdocParser($flag_output = false) { if ($flag_output) $this->setFlagOutput(true); else $this->setFlagOutput(false); $this->buildComplexRegExps(); } // end constructor /** * Central parsing function. * * With version 0.3alpha PHPdoc changed the way the parser works. It does now * 1 1/2 parsing runs. One prescan to build the class trees and a list of module * groups and one deep scan to extract the information. This reduces the memory * consumption. * * @return boolean $ok * @access public * @see findModulegroups(), findClassTrees(), getModulesAndClasses() */ function preparse() { if (0 == count($this->phpfiles)) { $this->err[] = new PHPDocError("Can't parse - no files defined.", __FILE__, __LINE__); return false; } $para = array(); reset($this->phpfiles); while (list($filename, $phpcode) = each($this->phpfiles)) $para[$filename] = $this->getModulesAndClasses($phpcode); $this->findModulegroups($para); $this->findClassTrees($para); return true; } // end func preparse /** * Returns the data of one parentclass and all it's subclasses or false. * * Use this function to loop through the class trees. The loop should look somewhat like: * <code>while ( $classtree = $parser->getClassTree() ) ...</code> * * @return mixed $classes Hash with the data of the current class tree or false. * @access public * @see getModulegroup(), $baseclasses */ function getClassTree() { // first call, reset the baseclass array pointer if (!$this->flag_classtree) { reset($this->baseclasses); $this->flag_classtree = true; } if (list($classname, $filename) = each($this->baseclasses)) { $this->classes = array(); $this->current_baseclass = $classname; $this->addClass($classname, $filename); return $this->classes; } else { return false; } } // end func getClassTree /** * Returns the data of one module group. * * Use this function to loop through the module groups. The loop should look somewhat like: * <code>while ( $modulegroup = $parser->getModulegroup() ) ...</code>. * * @return mixed $modulegroup Hash with the data of the current class tree or false. * @access public * @see getClassTree(), addModule(), $modulegroups */ function getModulegroup() { if (!$this->flag_modulegroup) { reset($this->modulegroups); $this->flag_modulegroup = true; } if (list($group, $modules) = each($this->modulegroups)) { $this->modules = array(); while (list($modulename, $files) = each($modules)) { reset($files); while (list($k, $filename) = each($files)) $this->addModule($group, $filename); } return $this->modules; } else { return false; } } // end func getModulegroup /** * Analyses the given file and adds the result to the module list. * * The function analyses the given file, unsets the file in the * file list, adds the result of the parser to the module list and * if necessary it adds some data to the package list. * * @param string Name of the module group the parsing result gets added. * @param string Name of the file to scan. * @see getPhpdocParagraphs(), analyseModule() */ function addModule($group, $filename) { $data = $this->getPhpdocParagraphs($this->phpfiles[$filename], array("classes", "variables") ); // free memory as soon as possible... unset($this->phpfiles[$filename]); // note: not passed by argument $this->currentFile = $filename; $result = $this->analyseModule($data); $result["filename"] = $filename; $this->modules[$group][$result["name"]] = $result; if (isset($result["package"])) $this->packages[$result["package"]]["modules"][] = array ( "name" => $result["name"], "group" => $result["group"], "filename" => $filename ); } // end func addModule /** * Analyses the given file and adds the result to the class list. * * The first parameter (classname) comes from the prescan done * by findClassTrees() * * @param string Name of the class that gets added. * @param string Name of the file to scan. * @see addSubclasses(), analyseClass(), $classes */ function addClass($classname, $filename) { $data = $this->getPhpdocParagraphs($this->phpfiles[$filename], array("modules") ); // free memory as soon as possible... unset($this->phpfiles[$filename]); $this->currentFile = $filename; $result = $this->analyseClass($data); // Add some informations from the classtree that was build by the prescan to the class. $fields = array("subclasses", "noparent", "path", "baseclass"); reset($fields); while (list($k, $field) = each($fields)) if (isset($this->classtree[$filename][$classname][$field])) $result[$field] = $this->classtree[$filename][$classname][$field]; $result["filename"] = $filename; $this->classes[$classname] = $result; $this->addSubclasses($classname); if (isset($result["package"])) $this->packages[$result["package"]]["classes"][] = $classname; } // end func addClass /** * Adds recursively subclasses to the specified class. * * @param string Name of the class that might contain subclasses * @see addClass() */ function addSubclasses($classname) { if (isset($this->classes[$classname]["subclasses"])) { $subclasses = $this->classes[$classname]["subclasses"]; while (list($subclass, $v) = each($subclasses)) $this->addClass($subclass, $this->classnamesToFilenames[$subclass]); } } // end func addSubclasses /** * Builds the hash of module groups and the module file list. * * @param array Hash with the result of getClassesAndModules() of all files * @see parse(), findClassTree(), $modulegroups, $modulefiles */ function findModulegroups($para) { reset($para); while (list($filename, $data) = each($para)) { if (isset($data["modules"]["name"])) { $name = ("" != $data["modules"]["name"]) ? $data["modules"]["name"] : $filename; $group = ("" != $data["modules"]["group"]) ? $data["modules"]["group"] : $name; if (0 != count($data["classes"])) { // As we do not have a real parser that returns a parsing tree we can't // handle modules and classes in one file. Drop a note to the user. $this->warn->addDocWarning( $filename, "module", $name, "PHPDoc is confused: module files must not contain classes. Doc will probably be broken, module gets ignored.", "collision" ); continue; } if (isset($this->modulegroups[$group][$name])) $this->warn->addDocWarning($filename, "module", $name, "Warning: there's more than one module '$name' (file: '$filename) in the module group '$group'.", "warning"); $this->modulegroups[$group][$name][] = $filename; $this->modulefiles[] = $filename; } } } // end func findModulegroups /** * Builds a hash of all class trees. * * @param array Hash with the result of getClassesAndModules() of all files * @see parse(), findModulegroups(), $classnamesToFilenames, $classtree, $classfiles, $baseclasses */ function findClassTrees($para) { reset($para); while(list($filename, $data) = each($para)) { if (0!=count($data["classes"])) { $classname = $data["classes"][0]["name"]; if (1<count($data["classes"])) $this->warn->addDocWarning($filename, "class", $classname , "PHPDoc is confused: there is more than one class in this file. Doc will probably be broken, first class '$classname' gets used, file '$filename' get ignored.", "collision"); if (isset($data["modules"]["name"])) $this->warn->addDocWarning($filename, "class", "", "Warning: found a module comment in a class file. Module comment gets ignored, doc might be broken.", "collision"); $this->classnamesToFilenames[$classname] = $filename; $this->classtree[$filename][$classname] = $data["classes"][0]; $this->classfiles[] = $filename; } } reset($this->classnamesToFilenames); while (list($classname, $filename)=each($this->classnamesToFilenames)) { $path = array(); $baseclass = $classname; $basefile = $filename; $flag_noparent = false; while ($extends = $this->classtree[$basefile][$baseclass]["extends"]) { if (!isset($this->classnamesToFilenames[$extends])) { $flag_noparent = true; break; } $this->classtree[$this->classnamesToFilenames[$extends]][$extends]["subclasses"][$baseclass] = true; $path[] = $extends; $baseclass = $extends; $basefile = $this->classnamesToFilenames[$baseclass]; } if ($flag_noparent) $this->classtree[$filename][$classname]["noparent"] = $flag_noparent; $base = (0 == count($path)) ? true : false; if ($base) $this->baseclasses[$classname] = $filename; else $this->classtree[$filename][$classname]["path"] = $path; if ($baseclass != $classname) $this->classtree[$filename][$classname]["baseclass"] = $baseclass; } } // end func findClassTrees /** * Returns the mapping array from classnames to filenames * * @return array * @see $classnamesToFilenames */ function getClassnamesToFilenames() { return $this->classnamesToFilenames; } // end func getClassnamesToFilenames /** * Sets the list of PHP Soucecode Files to examine. * @param array $phpfiles * @return bool $ok * @access public */ function setPhpSourcecodeFiles($phpfiles) { if (!is_array($phpfiles) || 0 == count($phpfiles)) return false; $this->phpfiles = $phpfiles; return true; } // end func setPhpSourcecodeFiles } // end class PhpdocParser ?>